import Vue from 'vue';
import { Subject, Subscription } from 'rxjs';
import { Component, Prop } from 'vue-property-decorator';
import VueDraggableResizable from 'vue-draggable-resizable';
import 'vue-draggable-resizable/dist/VueDraggableResizable.css';
import { CtrlEvent, ISheetParam } from '../../interface';
import { AppVisualCtrlItem } from '../app-visual-ctrl-item/app-visual-ctrl-item';
import './app-visual-grid.less';
import { AppVisualGridService } from './app-visual-grid-service';
import { SheetUtil } from '../../utils/';
import { IPSDEGrid } from '@ibiz/dynamic-model-api';

/**
 * 自定义绘制虚拟表格控件
 *
 * @export
 * @class AppVisualGrid
 * @extends {Vue}
 */
@Component({
    components: {
        'vue-draggable-resizable': VueDraggableResizable
    }
})
export class AppVisualGrid extends Vue {

    /**
     * 表格列
     *
     * @type {*}
     * @memberof AppVisualGrid
     */
    @Prop() columnArray!: any;

    /**
     * 控件位置
     *
     * @type {*}
     * @memberof AppVisualGrid
     */
    @Prop() position!: any;

    /**
     * 控件ID
     *
     * @type {*}
     * @memberof AppVisualGrid
     */
    @Prop() id!: string;

    /**
     * 是否可设计控件
     *
     * @type {*}
     * @memberof AppVisualGrid
     */
    @Prop() enableDesgin?: boolean;

    /**
     * @description sheet状态通知对象
     * @type {Subject<ISheetParam>}
     * @memberof AppVisualGrid
     */
    @Prop() public sheetState !: Subject<ISheetParam>;

    /**
     * @description 是否激活
     * @type {boolean}
     * @memberof AppVisualGrid
     */
    public isActiveCtrl: boolean = false;

    /**
     * sheet状态事件
     *
     * @public
     * @type {(Subscription | undefined)}
     * @memberof AppVisualGrid
     */
    public sheetStateEvent: Subscription | undefined;

    /**
     * @description 虚拟表格服务
     * @private
     * @type {AppVisualGridService}
     * @memberof AppVisualGrid
     */
    private service!: AppVisualGridService;

    /**
     * @description 真实组件引用
     * @private
     * @type {*}
     * @memberof AppVisualGrid
     */
    private realCompRef: any;

    /**
     * @description 表格部件实例对象
     * @private
     * @type {IPSDEGrid}
     * @memberof AppVisualGrid
     */
    private controlInstance!: IPSDEGrid;

    /**
     * @description 获取部件可操作性区域
     * @readonly
     * @memberof AppVisualGrid
     */
    public getCtrlRange() {
        if (this.service) {
            return this.service.getCtrlRange();
        }
        return {};
    }

    /**
     * @description 部件初始化
     * @memberof AppVisualGrid
     */
    public created() {
        if (this.sheetState) {
            this.sheetStateEvent = this.sheetState.subscribe(({ tag, action, data }: { tag: string, action: string, data: any }) => {
                if (!Object.is(tag, this.id)) {
                    return;
                }
                if (Object.is(action, 'CELLMOUSEDOWN')) {
                    this.handleCellMouseDown(data);
                }
                if (Object.is(action, 'UPDATE')) {
                    this.handleSheetUpdate(data);
                }
                if (Object.is(action, 'CLEAR')) {
                    this.handClearAll(data);
                }
            })
        }
    }

    /**
     * @description 挂载完成
     * @memberof AppVisualGrid
     */
    public mounted() {
        const refNode = (this.$slots.default as any[])[0];
        refNode.componentInstance.$on('ctrl-event', (args: any) => {
            const { controlname, action, data } = args;
            if (Object.is(action, 'controlIsMounted')) {
                this.realCompRef = refNode.componentInstance.$refs.ctrl;
                this.controlInstance = this.realCompRef.controlInstance;
                this.service = new AppVisualGridService({
                    controlInstance: this.controlInstance,
                    context: this.realCompRef.context,
                    viewParam: this.realCompRef.viewparams,
                    codeListService: this.realCompRef.codeListService
                });
                this.service.initBasicData(this.columnArray);
                if (this.enableDesgin) {
                    this.service.initVisualCtrl(this.position);
                }
            }
            if (Object.is(action, 'onloadsuccess')) {
                this.service.initVisualCtrl(this.position, data.data).then((result: any) => {
                    this.mountedVisualCtrl(result);
                })
            }
        })
    }

    /**
     * @description 挂载虚拟表格
     * @param {*} data
     * @memberof AppVisualGrid
     */
    public mountedVisualCtrl(data: any) {
        if (data && data.luckyGridData && data.luckyGridData.length > 0) {
            SheetUtil.setConfig(data.sheetConfig.config);
            data.luckyGridData.forEach((element: any) => {
                if (element.options) {
                    SheetUtil.setCellValue(element.r, element.c, element.options);
                }
            });
        }
        this.$emit(CtrlEvent.INITD, this.getEmitParam(this.getOutParam()));
    }


    /**
     * @description 挂载控件项
     * @param {*} item 控件项
     * @param {*} position 控件位置
     * @memberof AppVisualGrid
     */
    public mountedCtrlItem(item: any, position: any) {
        let _this = this;
        const tempPosition = {
            left: position.start_c,
            top: position.start_r,
            width: position.end_c - position.start_c - 2,
            height: position.end_r - position.start_r - 2
        };
        const props = {
            realCompRef: _this.realCompRef.$refs[item.codeName]?.$refs['editor']?.$refs['editor'],
            detailInstance: item['editColumn'],
            position: tempPosition,
            type: 'GRID',
            id: `${item['codeName']}-${position['r']}`,
            value: item['v'],
            rowIndex: position['r'],
            colIndex: position['c'],
            rowData: item['originalData']
        };
        const vm = new Vue({
            render(h) {
                return h(AppVisualCtrlItem,
                    {
                        props,
                        on: {
                            change: (data: any) => {
                                _this.handleCtrlItemValueChange(data);
                            }
                        }
                    });
            }
        }).$mount();
        SheetUtil.getElement('#luckysheet-ctrl-showBoxs .ctrl-list').append(vm.$el);
    }

    /**
     * @description 获取抛出参数
     * @param {*} data
     * @return {*} 
     * @memberof AppVisualGrid
     */
    public getEmitParam(data: any) {
        return {
            id: this.id,
            type: 'GRID',
            ...data
        }
    }

    /**
     * @description 获取抛出参数
     * @readonly
     * @memberof AppVisualGrid
     */
    public getOutParam() {
        return {
            position: this.service.getCtrlRange(),
            sheetConfig: this.service.getSheetConfig(),
            columns: this.columnArray
        };
    }

    /**
     * @description 处理控件项值变化
     * @param {*} data 抛出值
     * @memberof AppVisualGrid
     */
    public handleCtrlItemValueChange(data: any) {
        const { rowData, event, rowIndex, colIndex } = data;
        // 设置当前单元格值
        (window as any).luckysheet.setCellValue(rowIndex, colIndex, event.value);
        // 设置虚拟控件数据
        this.service.setVisualCtrlData(rowIndex - this.position.startRow - 1, event.name, event.value);
        // 设置原生控件数据
        if (this.realCompRef.onGridItemValueChange instanceof Function) {
            this.realCompRef.onGridItemValueChange(rowData, event, rowIndex - this.position.startRow - 1);
        }
    }

    /**
     * @description 控件变化
     * @param {*} operate
     * @memberof AppVisualGrid
     */
    public handleSheetUpdate(operate: any) {
        const { type, curConfig, curconfig, curData, curdata } = operate;
        let emitConf = curConfig ? curConfig : curconfig ? curconfig : {};
        if (Object.is(type, 'resize')) {
            SheetUtil.getElement('.app-visual-ctrl-item').remove();
            const position = this.getCtrlRange();
            this.service.updateColumnLen(position, emitConf?.columnlen);
            this.service.initCtrlRange(position, false);
            this.service.setSheetConfig({ config: emitConf });
            this.$emit(CtrlEvent.RESIZE, this.getEmitParam(this.getOutParam()));
        }
    }

    /**
     * @description 控件单元格点击
     * @param {*} data
     * @memberof AppVisualGrid
     */
    public handleCellMouseDown(data: any) {
        const { cell, position, sheetFile } = data;
        if (cell?.link) {
            this.handleCellLink(cell);
            return;
        }
        if (cell && cell.codeName && cell.enableRowEdit) {
            // 清空所有编辑项
            SheetUtil.getElement('.app-visual-ctrl-item').remove();
            this.mountedCtrlItem(cell, position);
        } else {
            this.isActiveCtrl = this.service.checkSelectedCtrl(position, this.service.getCtrlRange());
            if (this.isActiveCtrl) {
                this.$emit(CtrlEvent.ACTIVATED, this.getEmitParam(this.getOutParam()));
            } else {
                this.$emit(CtrlEvent.DEACTIVATED, this.getEmitParam(this.getOutParam()));
            }
        }
    }

    /**
     * @description 处理单元格链接
     * @param {*} cell
     * @return {*} 
     * @memberof AppCtrlGrid
     */
    public handleCellLink(cell: any) {
        if (!this.realCompRef) {
            return;
        }
    }

    /**
     * @description 控件清除
     * @param {*} data
     * @memberof AppVisualGrid
     */
    public handClearAll(data: any) {
        if (!data) {
            return;
        }
        this.service.clearSelectedRange(data.position);
    }

    /**
     * @description 处理取消激活
     * @param {*} data
     * @memberof AppVisualGrid
     */
    public handleDeActived(data: any) {
        const { cell, position, sheetFile } = data;
        this.$emit(CtrlEvent.DEACTIVATED, this.getEmitParam(this.getOutParam()));
    }

    /**
     * @description 拖拽
     * @param {*} x left偏移
     * @param {*} y top偏移
     * @memberof AppVisualGrid
     */
    public handleDragstop(x: any, y: any) {
        this.service.clearSelectedRange(this.service.getCtrlRange());
        const result = this.service.initVisualGrid(this.service.compPosition(x, y), false);
        this.mountedVisualCtrl(result);
        this.isActiveCtrl = false;
        this.$forceUpdate();
        this.$emit(CtrlEvent.DRAG, this.getEmitParam(this.getOutParam()));
    }

    /**
     * @description 处理删除部件
     * @param {MouseEvent} event
     * @memberof AppVisualGrid
     */
    public handleRemove(event: MouseEvent) {
        event.stopPropagation();
        this.$emit(CtrlEvent.REMOVE, this.getEmitParam(this.getOutParam()));
    }

    /**
     *  @description 组件销毁
     * 
     * @memberof AppSheetDesign
     */
    public destory() {
        if (this.sheetStateEvent) {
            this.sheetStateEvent.unsubscribe();
        }
    }

    /**
     * @description 绘制虚拟表格控件
     * @return {*} 
     * @memberof AppVisualGrid
     */
    public render() {
        const ctrlRange = this.getCtrlRange();
        return (<div class="app-visual-grid">
            {this.isActiveCtrl && this.enableDesgin ?
                <vue-draggable-resizable draggable={this.enableDesgin} resizable={false}
                    style={{ zIndex: 301 }} w={ctrlRange.width} h={ctrlRange.height}
                    x={ctrlRange.left - 1} y={ctrlRange.top - 2} active={true}
                    onDragstop={(x: number, y: number) => { this.handleDragstop(x, y) }}
                >
                    <div style="width:100%;height:100%;overflow:hidden; background-color: rgb(235,235,235,0.8);"></div>
                </vue-draggable-resizable> : null
            }
            <div
                class={[this.isActiveCtrl && this.enableDesgin ? '' : 'is-hidden', "luckysheet-modal-dialog-controll"]}
                style={{
                    left: `${ctrlRange.width + ctrlRange.left}px`,
                    top: `${ctrlRange.top}px`,
                    zIndex: 300
                }}>
                <span class="luckysheet-modal-controll-btn" onClick={(event: MouseEvent) => { this.handleRemove(event); }}>
                    <i class="fa fa-trash" />
                </span>
            </div>
            <div class="main-content">
                {this.$slots.default}
            </div>
        </div>)
    }

}